package com.xiaozhen.rtmp.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.crypto.digest.MD5;
import com.xiaozhen.rtmp.common.ClientType;
import com.xiaozhen.rtmp.domain.Camera;
import com.xiaozhen.rtmp.service.MediaService;
import com.xiaozhen.rtmp.thread.MediaTransfer;
import com.xiaozhen.rtmp.thread.MediaTransferFlvByFFmpeg;
import com.xiaozhen.rtmp.thread.MediaTransferFlvByJavacv;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.stereotype.Service;

/**
 * HISTORY
 *
 * @author zhenweisheng
 * @date 2021/12/6 16:30
 * @description:
 */
@Service
public class MediaServiceImpl implements MediaService {

    @Override
    public boolean playForApi(Camera camera) {
        // 区分不同媒体
        String mediaKey = MD5.create().digestHex(camera.getUrl());
        camera.setMediaKey(mediaKey);
        camera.setFlv(true);

        MediaTransfer mediaTransfer = cameras.get(camera.getMediaKey());
        if (null == mediaTransfer) {
            if(camera.getFfmpeg()) {
                MediaTransferFlvByFFmpeg mediaft = new MediaTransferFlvByFFmpeg(camera);
                mediaft.execute();
                cameras.put(camera.getMediaKey(), mediaft);
            } else {
                MediaTransferFlvByJavacv mediaConvert = new MediaTransferFlvByJavacv(camera);
                cameras.put(camera.getMediaKey(), mediaConvert);
                ThreadUtil.execute(mediaConvert);
            }
        }

        mediaTransfer = cameras.get(camera.getMediaKey());
        //同步等待
        if(mediaTransfer instanceof MediaTransferFlvByJavacv) {
            MediaTransferFlvByJavacv mediaft = (MediaTransferFlvByJavacv) mediaTransfer;
            // 30秒还没true认为启动不了
            for (int i = 0; i < 60; i++) {
                if (mediaft.isRunning() && mediaft.isGrabberStatus() && mediaft.isRecorderStatus()) {
                    return true;
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
            }
        } else if (mediaTransfer instanceof MediaTransferFlvByFFmpeg) {
            MediaTransferFlvByFFmpeg mediaft = (MediaTransferFlvByFFmpeg) mediaTransfer;
            // 30秒还没true认为启动不了
            for (int i = 0; i < 60; i++) {
                if (mediaft.isRunning()) {
                    return true;
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
            }
        }
        return false;
    }

    @Override
    public void playForHttp(Camera camera, ChannelHandlerContext ctx) {
        if (cameras.containsKey(camera.getMediaKey())) {
            MediaTransfer mediaConvert = cameras.get(camera.getMediaKey());
            if(mediaConvert instanceof MediaTransferFlvByJavacv) {
                MediaTransferFlvByJavacv mediaTransferFlvByJavacv = (MediaTransferFlvByJavacv) mediaConvert;
                //如果当前已经用ffmpeg，则重新拉流
                if(camera.getFfmpeg()) {
                    mediaTransferFlvByJavacv.setRunning(false);
                    cameras.remove(camera.getMediaKey());
                    this.playForHttp(camera, ctx);
                } else {
                    mediaTransferFlvByJavacv.addClient(ctx, ClientType.HTTP);
                }
            } else if (mediaConvert instanceof MediaTransferFlvByFFmpeg) {
                MediaTransferFlvByFFmpeg mediaTransferFlvByFFmpeg = (MediaTransferFlvByFFmpeg) mediaConvert;
                //如果当前已经用javacv，则关闭再重新拉流
                if(!camera.getFfmpeg()) {
                    mediaTransferFlvByFFmpeg.stopFFmpeg();
                    cameras.remove(camera.getMediaKey());
                    this.playForHttp(camera, ctx);
                } else {
                    mediaTransferFlvByFFmpeg.addClient(ctx, ClientType.HTTP);
                }
            }

        } else {
            if(camera.getFfmpeg()) {
                MediaTransferFlvByFFmpeg mediaft = new MediaTransferFlvByFFmpeg(camera);
                mediaft.execute();
                cameras.put(camera.getMediaKey(), mediaft);
                mediaft.addClient(ctx, ClientType.HTTP);
            } else {
                MediaTransferFlvByJavacv mediaConvert = new MediaTransferFlvByJavacv(camera);
                cameras.put(camera.getMediaKey(), mediaConvert);
                ThreadUtil.execute(mediaConvert);
                mediaConvert.addClient(ctx, ClientType.HTTP);
            }

        }
    }

    @Override
    public void playForWs(Camera camera, ChannelHandlerContext ctx) {
        if (cameras.containsKey(camera.getMediaKey())) {
            MediaTransfer mediaConvert = cameras.get(camera.getMediaKey());
            if(mediaConvert instanceof MediaTransferFlvByJavacv) {
                MediaTransferFlvByJavacv mediaTransferFlvByJavacv = (MediaTransferFlvByJavacv) mediaConvert;
                //如果当前已经用ffmpeg，则重新拉流
                if(camera.getFfmpeg()) {
                    mediaTransferFlvByJavacv.setRunning(false);
                    cameras.remove(camera.getMediaKey());
                    this.playForWs(camera, ctx);
                } else {
                    mediaTransferFlvByJavacv.addClient(ctx, ClientType.WEBSOCKET);
                }
            } else if (mediaConvert instanceof MediaTransferFlvByFFmpeg) {
                MediaTransferFlvByFFmpeg mediaTransferFlvByFFmpeg = (MediaTransferFlvByFFmpeg) mediaConvert;
                //如果当前已经用javacv，则关闭再重新拉流
                if(!camera.getFfmpeg()) {
                    mediaTransferFlvByFFmpeg.stopFFmpeg();
                    cameras.remove(camera.getMediaKey());
                    this.playForWs(camera, ctx);
                } else {
                    mediaTransferFlvByFFmpeg.addClient(ctx, ClientType.WEBSOCKET);
                }
            }
        } else {
            if(camera.getFfmpeg()) {
                MediaTransferFlvByFFmpeg mediaft = new MediaTransferFlvByFFmpeg(camera);
                mediaft.execute();
                cameras.put(camera.getMediaKey(), mediaft);
                mediaft.addClient(ctx, ClientType.WEBSOCKET);
            } else {
                MediaTransferFlvByJavacv mediaConvert = new MediaTransferFlvByJavacv(camera);
                cameras.put(camera.getMediaKey(), mediaConvert);
                ThreadUtil.execute(mediaConvert);
                mediaConvert.addClient(ctx, ClientType.WEBSOCKET);
            }
        }
    }

    /**
     * 关闭流
     * @param camera
     */
    @Override
    public void closeForApi(Camera camera) {
        camera.setFlv(false);

        if (cameras.containsKey(camera.getMediaKey())) {
            MediaTransfer mediaConvert = cameras.get(camera.getMediaKey());
            if(mediaConvert instanceof MediaTransferFlvByJavacv) {
                MediaTransferFlvByJavacv mediaTransferFlvByJavacv = (MediaTransferFlvByJavacv) mediaConvert;
                mediaTransferFlvByJavacv.setRunning(false);
                cameras.remove(camera.getMediaKey());
            } else if (mediaConvert instanceof MediaTransferFlvByFFmpeg) {
                MediaTransferFlvByFFmpeg mediaTransferFlvByFFmpeg = (MediaTransferFlvByFFmpeg) mediaConvert;
                mediaTransferFlvByFFmpeg.stopFFmpeg();
                cameras.remove(camera.getMediaKey());
            }
        }
    }
}
